package top.saplf.sileny.player.home

import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.*
import android.support.v4.app.SharedElementCallback
import android.support.v4.content.ContextCompat
import android.support.v7.app.AppCompatActivity
import android.util.Base64
import android.view.View
import com.bumptech.glide.Glide
import com.jakewharton.rxbinding2.view.clicks
import io.reactivex.disposables.Disposable
import io.realm.Realm
import io.realm.RealmResults
import kotlinx.android.synthetic.main.activity_local_music.*
import me.eugeniomarletti.extras.intent.IntentExtra
import me.eugeniomarletti.extras.intent.base.String
import top.saplf.sileny.R
import top.saplf.sileny.base.ui.IActivity
import top.saplf.sileny.ext.blur
import top.saplf.sileny.ext.normalCompose
import top.saplf.sileny.net.netease.NetEaseService
import top.saplf.sileny.player.home.PlayMusicService.Companion.PLAY_PROGRESS

/**
 * @author saplf
 */
class LocalMusicActivity : AppCompatActivity(), IActivity {

    companion object {
        var Intent.musicId: String by IntentExtra.String("")

        const val RESULT_CODE = 1
    }

    private val mRealm: Realm by lazy { Realm.getDefaultInstance() }
    private val mMusic: Music
        get() = mMusicList.find { it.id == intent.musicId }!!
    private val mMusicList: RealmResults<Music> by lazy {
        mRealm.where(Music::class.java).findAll().sort(Music::name.name)
    }
    private val mSharedElementCallback: SharedElementCallback by lazy {
        object : SharedElementCallback() {
            override fun onMapSharedElements(names: MutableList<String>, sharedElements: MutableMap<String, View>) {
                val id = intent.musicId
                names.clear()
                names.add(id)
                sharedElements.clear()
                sharedElements.put(id, cover)
            }
        }
    }
    private val mColorDrawable: Drawable by lazy { ColorDrawable(ContextCompat.getColor(this, R.color.colorPrimary)) }

    private var mServiceMessenger: Messenger? = null
    private val mActivityMessenger: Messenger by lazy { Messenger(mHandler) }
    private var mPlaying: Boolean = false
    private val mHandler: Handler by lazy {
        Handler {
            when (it.what) {
                PLAY_PROGRESS -> {
                    with(PlayMusicService) {
                        lrcView.updateTime(it.data.playProgress.toLong())
                        mPlaying = it.data.isPlaying
                    }
                }
            }
            true
        }
    }
    private val mConnection: ServiceConnection by lazy {
        object : ServiceConnection {
            override fun onServiceDisconnected(name: ComponentName?) {

            }

            override fun onServiceConnected(name: ComponentName?, service: IBinder) {
                mServiceMessenger = Messenger(service)

                Message.obtain().apply {
                    what = PlayMusicService.CONNECTED
                    replyTo = mActivityMessenger
                    mServiceMessenger?.send(this)
                }

                mMusic.apply {
                    Message.obtain().apply {
                        what = PlayMusicService.START
                        data = Bundle().apply { with(PlayMusicService) { musicPath = path } }
                        mServiceMessenger?.send(this)
                    }
                }
            }

        }
    }

    override fun onLayoutRes(): Int = R.layout.activity_local_music

    override fun onViewCreated(savedInstanceState: Bundle?) {
        setEnterSharedElementCallback(mSharedElementCallback)

        switchTo(mMusic)

        postMusic.clicks()
                .subscribe {
                    mMusic.run {
                        var index = mMusicList.indexOf(this) + 1
                        if (index >= mMusicList.size) {
                            index = 0
                        }
                        switchTo(mMusicList[index])
                    }
                }

        prevMusic.clicks()
                .subscribe {
                    mMusic.run {
                        var index = mMusicList.indexOf(this) - 1
                        if (index < 0) {
                            index = mMusicList.size - 1
                        }
                        switchTo(mMusicList[index])
                    }
                }

        cover.clicks()
                .subscribe {
                    if (mPlaying) {
                        (controller.background as AnimatedVectorDrawable).start()
                    } else {
                        val animatedVectorDrawable = controller.background as AnimatedVectorDrawable
                        val clazz = AnimatedVectorDrawable::class.java
                        val method = clazz.getMethod("reverse")
                        method.invoke(animatedVectorDrawable)
                    }
                    mMusic.apply {
                        Message.obtain().apply {
                            what = if (mPlaying) PlayMusicService.PAUSE else PlayMusicService.START
                            data = Bundle().apply { with(PlayMusicService) { musicPath = path } }
                            mServiceMessenger?.send(this)
                        }
                    }
                }

        startService(Intent(this, PlayMusicService::class.java))
        bindService(Intent(this, PlayMusicService::class.java), mConnection, 0)
    }

    override fun onDestroy() {
        super.onDestroy()
        mRealm.close()
        unbindService(mConnection)
    }

    private var mDisposable: Disposable? = null
    private fun switchTo(music: Music) {
        intent.musicId = music.id

        if (music.cover.isNullOrEmpty()) {
            cover.setImageResource(R.mipmap.book_bg)
            background.setImageDrawable(mColorDrawable)
        } else {
            val byteArray: ByteArray = Base64.decode(music.cover, Base64.DEFAULT)
            val bitmap: Bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
            Glide.with(this)
                    .load(byteArray)
                    .dontAnimate()
                    .into(cover)
            background.setImageBitmap(bitmap.blur())
        }

        cover.transitionName = music.id

        musicName.text = music.name
        singer.text = "${music.author} | ${music.album}"

        mDisposable?.dispose()
        if (mMusic.lrc == null) {
            mDisposable = NetEaseService.getNetEaseService()
                    .searchSongs(music.name, 0, 10, NetEaseService.SONG)
                    .filter { it.isSuccess() }
                    .filter { it.result != null }
                    .map { it.result!! }
                    .filter { it.songCount > 0 }
                    .map { it.songs!![0] }
                    .flatMap { NetEaseService.getNetEaseService().obtainLrc(it.id) }
                    .filter { it.isSuccess() }
                    .filter { it.lrc != null }
                    .map { it.lrc!! }
                    .filter { !it.lyric.isNullOrEmpty() }
                    .map { it.lyric!! }
                    .normalCompose(this)
                    .doAfterNext {
                        mRealm.beginTransaction()
                        mMusic.lrc = it
                        mRealm.commitTransaction()
                    }
                    .subscribe { lrcView.loadLrc(it) }
        } else {
            lrcView.loadLrc(mMusic.lrc)
        }

        music.apply {
            Message.obtain().apply {
                what = PlayMusicService.START
                data = Bundle().apply { with(PlayMusicService) { musicPath = path } }
                mServiceMessenger?.send(this)
            }
        }
    }

    override fun finishAfterTransition() {
        setResult(RESULT_CODE, Intent().apply {
            musicId = intent.musicId
        })

        super.finishAfterTransition()
    }

}